package com.ecoolex.union.pay.retailer.core.util;

import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.exception.BizException;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.union.pay.retailer.core.properties.UnionPayUplanPropertis;
import com.ecoolex.union.pay.retailer.core.util.unionpay.LogUtil;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.io.Resource;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.stereotype.Service;
import org.springframework.util.comparator.Comparators;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateCrtKey;
import java.util.Base64;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

@Service
@EnableConfigurationProperties(UnionPayUplanPropertis.class)
@EnableRetry
public class UnionPayUplanService {

    @Autowired
    Gson gson;

    @Autowired
    RestTemplateBuilder restTemplateBuilder;

    @Autowired
    UnionPayUplanPropertis unionPayUplanPropertis;

    public static final String X509 = "X.509";

    /** 貌似默认是RSA/NONE/PKCS1Padding，未验证 */
    public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";

    /**
     * 最大文件加密块
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * 最大文件解密块
     */
    private static final int MAX_DECRYPT_BLOCK = 256;



    /**
     *  对数据进行签名
     * @param orgin 原文
     * @return 签名值
     */
    public byte[] signData(String orgin) {
        try {
            Resource resource = unionPayUplanPropertis.getSignature().getPrivateKey();
            char[] charPassword = unionPayUplanPropertis.getSignature().getPassword().toCharArray();
            String alias = "";
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(resource.getInputStream(),charPassword);
            Enumeration<String> e = keyStore.aliases();
            if (e.hasMoreElements()){
                alias = (String)e.nextElement();
            }
            LogUtil.writeLog(String.format("signData:%s",orgin));
            RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyStore.getKey(alias, charPassword);
            Signature sign = Signature.getInstance("SHA256WithRSA");
            sign.initSign(privateKey);
            byte[] bysData = orgin.getBytes(StandardCharsets.UTF_8);
            sign.update(bysData);
            byte[] signByte = sign.sign();
            return signByte;
        }catch (Exception e){
            LogUtil.writeErrorLog("签名失败", e);
            throw new BizException(ResultCode.CALL.build(97),"签名失败");
        }
    }

    /**
     * 验证签名
     * @param plainText 原文
     * @param signature 签名
     * @return 是否验签通过
     */
    public boolean verify(String plainText, String signature) {
        try {
            Resource publicKeyResource = unionPayUplanPropertis.getSignature().getPublicKey();
            CertificateFactory certificatefactory = CertificateFactory.getInstance(X509);
            X509Certificate cert = (X509Certificate) certificatefactory.generateCertificate(publicKeyResource.getInputStream());
            PublicKey publicKey = cert.getPublicKey();
            Signature publicSignature  = Signature.getInstance("SHA256WithRSA");
            publicSignature.initVerify(publicKey);
            publicSignature.update(plainText.getBytes(StandardCharsets.UTF_8));
            LogUtil.writeLog(String.format("原数据:%s",signature));
            signature = URLDecoder.decode(signature,"UTF-8").replace(" ","+");
            LogUtil.writeLog(String.format("urldecode:%s",signature));
            byte[] signatureBytes = Base64.getDecoder().decode(signature);
            return publicSignature.verify(signatureBytes);
        }catch (Exception e){
            LogUtil.writeErrorLog("验签失败", e);
            throw new BizException(ResultCode.CALL.build(98),"验签失败");
        }
    }

    public String build(Map<String, String> params) {
        Iterator<String> sorted = params.keySet().stream().filter(name ->!"sign".equals(name)).sorted(Comparators.comparable())
                .iterator();
        StringBuilder stringBuilder = new StringBuilder();
        while (sorted.hasNext()){
            String name = sorted.next();
            String value = params.get(name);
            if(Check.notNull(value)){
                stringBuilder.append(name).append("=").append(value);
            }else {
                stringBuilder.append(name).append("=");
            }
            if(sorted.hasNext()){
                stringBuilder.append("&");
            }
        }
        return stringBuilder.toString();
    }
}
